<?php

// +----------------------------------------------------------------------
// | [基于ThinkPHP6.1开发]
// +----------------------------------------------------------------------
// | Copyright (c) 2016-2019 http://www.mcruanjian.com
// +----------------------------------------------------------------------
// +----------------------------------------------------------------------
// | 铭畅 技术部 出品
// +----------------------------------------------------------------------

namespace addons\WeChat\controller;

require_once __DIR__ . '/../sdk/include.php';
require_once __DIR__ . '/../sdk/Wxpay/WxPay.Api.php';

/**
 * @Author: Bryant
 * @Date: 2023-05-25 09:54:37
 * @method post
 * @title 公众号支付
 * @url
 */
class CodePay extends Base
{
    public $app_config;

    //返回实例本身
    public function __construct($config = null)
    {
        parent::__construct();
        if (is_array($config)) {
            $this->config = array_merge($this->config, $config);
        }

        $this->app_config = [
            'appid'        => $this->config['code_appid'],
            'appsecret'    => $this->config['code_appsecret'],
            // 配置商户支付参数（可选，在使用支付功能时需要）
            'mch_id'       => $this->config['mchid'],
            'mch_key'      => $this->config['key'],
            // 配置商户支付双向证书目录（可选，在使用退款|打款|红包时需要）
            'ssl_key'      => $this->config['sslkey_path'],
            'ssl_cer'      => $this->config['sslcert_path'],
            // 缓存目录配置（可选，需拥有读写权限）
            'cache_path'   => '',

            //V3部分
            'mch_v3_key'   => $this->config['key_v3'],
            'cert_public'  => $this->config['cert_public_v3'],
            'cert_private' => $this->config['cert_private_v3'],
        ];

        return $this;
    }

    /**
     * @Author: Bryant
     * @Date: 2023-05-25 09:54:47
     * @method post
     * @title 创建支付一个订单
     */
    public function pay($data)
    {
        $body         = $data['body'];
        $total_fee    = $data['total_fee'];
        $out_trade_no = $data['out_trade_no'];
        //组装订单数据
        $body = preg_replace('/\r\n/', '', $body);
        $body = mb_strlen($body) > 40 ? mb_substr($body, 0, 40, 'utf-8') . '...' : $body;

        $time = time();

        // 创建接口实例
        $wechat = new \WeChat\Pay($this->app_config);

        // 组装参数，可以参考官方商户文档
        $options = [
            'body'         => $body,
            'total_fee'    => $total_fee * 100,
            'out_trade_no' => $out_trade_no,
            'openid'       => $data['gzh_openid'],
            'trade_type'   => 'JSAPI',
            'notify_url'   => sysconfig('site', 'site_domain') . '/notify/wechat/wxcode',
        ];

        // 创建订单
        $result = $wechat->createOrder($options);
        if ($result['result_code'] == 'SUCCESS' && $result['return_code'] == 'SUCCESS') {
            // 创建微信端发起支付参数及签名
            $options = $wechat->createParamsForJsApi($result['prepay_id']);

            // 微信端发起支付参数及签名JSON化
            $params = json_encode($options);

            // 返回数据
            return $params;
        } else {
            return $result;
        }
    }

    /**
     * @Author: Bryant
     * @Date: 2023-05-25 09:54:55
     * @method post
     * @title 初始化实例
     */
    public function initWechatPay()
    {
        // 创建接口实例
        $wechat = new \WeChat\Pay($this->app_config);

        // 订单数据处理
        return $wechat;
    }

    //异步回调
    public function verifyNotify()
    {
        $notify = $this->WxPayNotify();
        $arr    = $notify->Handle();
        if ($arr['return_code'] != 'SUCCESS') {
            throw new \Exception($arr['return_msg']);
        }
        if ($arr['result_code'] != 'SUCCESS') {
            throw new \Exception($arr['err_code'] . $arr['err_code_des']);
        }
        //if($arr['trade_state'] != 'SUCCESS'){
        //    throw new \Exception($arr['trade_state_desc']);
        // }
        return $arr;
    }

    //私有方法实例化 异步类
    private function WxPayNotify()
    {
        require_once __DIR__ . '/../sdk/Wxpay/WxPay.Notify.php';
        static $notify = null;
        if (null === $notify) {
            $notify = new \WxPayNotify();
        }

        return $notify;
    }

    //同步回调
    public function verifyReturn($out_trade_no)
    {
        set_time_limit(2);
        $input = new \WxPayOrderQuery();
        $input->SetOut_trade_no($out_trade_no);
        $arr = \WxPayApi::orderQuery($input);
        if (!$arr) {
            throw new \Exception('订单查询失败');
        }
        if ($arr['return_code'] != 'SUCCESS') {
            throw new \Exception($arr['return_msg']);
        }
        if ($arr['result_code'] != 'SUCCESS') {
            throw new \Exception($arr['err_code'] . $arr['err_code_des']);
        }
        //此处到前端判断比较好
        //if($arr['trade_state'] != 'SUCCESS'){
        //    throw new \Exception($arr['trade_state_desc']);
        //}
        return $arr;
    }

    /**
     * 企业转账
     *   1、商户号（或同主体其他非服务商商户号）已入驻90日
     *   2、商户号（或同主体其他非服务商商户号）有30天连续正常交易
     *   3、 登录微信支付商户平台-产品中心，开通企业付款。
     * @param type $openid
     * @param type $money
     * @param type $true_name
     * @return type
     */
    public function transfers($openid, $amount, $partner_trade_no, $re_user_name, $desc)
    {

        $wechat = new \WePay\Transfers($this->app_config);
        $result = $wechat->create([
            "openid"           => $openid,
            "amount"           => $amount * 100,
            "partner_trade_no" => $partner_trade_no,
            "check_name"       => "NO_CHECK",
            "re_user_name"     => $re_user_name,
            "desc"             => $desc,
        ]);
        if ($result['return_code'] == 'FAIL') {
            throw new \Exception($result['return_msg']);
        }
        if ($result['result_code'] == 'FAIL') {
            throw new \Exception($result['err_code'] . ':' . $result['err_code_des']);
        }
        return $result;
    }

    /**
     * 商户转账到零钱V3
     * @param type $openid
     * @param type $money
     * @param type $true_name
     * @return type
     */
    public function transfersV3($openid, $amount, $partner_trade_no, $re_user_name, $desc)
    {

        $wechat = new \WePayV3\Transfers($this->app_config);
        //throw new InvalidResponseException
        $result = $wechat->batchs([
            "out_batch_no"         => "p" . $partner_trade_no,
            "batch_name"           => $desc,
            "batch_remark"         => $desc,
            "total_amount"         => bcmul($amount, 100, 0),
            "total_num"            => 1,
            "transfer_detail_list" => [
                [
                    "out_detail_no"   => $partner_trade_no,
                    "transfer_amount" => bcmul($amount, 100, 0),
                    "transfer_remark" => $desc,
                    "openid"          => $openid,
                    "user_name"       => $re_user_name,
                ],
            ],
        ]);
        return $result;
    }


    public function backPay($data)
    {
        $total_fee     = floatval($data['total_fee']);
        $refund_desc   = $data['refund_desc'];
        $refund_fee    = floatval($data['refund_fee']);
        $out_trade_no  = $data['out_trade_no'];
        $out_refund_no = $data['server_no'];

        $wechat  = new \WeChat\Pay($this->code_config);
        $options = [
            'total_fee'     => bcmul($total_fee, 100, 0), //订单总金额
            "out_trade_no"  => $out_trade_no,
            'out_refund_no' => $out_refund_no,
            'refund_fee'    => bcmul($refund_fee, 100, 0), //退款金额
            'refund_desc'   => $refund_desc, //退款理由
            'notify_url'    => config('web_site_domain') . '/notify/wechat/wxcodeBack',
        ];

        if ($transaction_id) {
            $options["transaction_id"] = $transaction_id;
            unset($options["out_trade_no"]);
        }
        // 创建退款订单
        $result = $wechat->createRefund($options);
        if ($result['return_code'] == 'FAIL') {
            throw new \Exception($result['return_msg']);
        }
        if ($result['result_code'] == 'FAIL') {
            throw new \Exception($result['err_code'] . ':' . $result['err_code_des']);
        }
        return $result;
    }

}
